import ws from "ws";
import { WebSocketServer } from "./WebSocketServer";
import { IncomingMessage } from "http";
import { agent } from "./agent";
import lyu from "../../lyu";
import lNetEvent from "./LNetEvent";
import msgpack from "msgpack-lite";


export default class LNet {
    public agentList: agent[] = [];

    private receiveFunc: { [x in string | number]: (ag: agent, data: any) => { id: number, msg: any } | void } = {};

    private ws: WebSocketServer;

    constructor(port: number) {
        this.ws = new WebSocketServer({ port: port });
        this.ws.onConnection = this.onConnection.bind(this);
        this.ws.onClose = this.onClose.bind(this);
        this.ws.listen();
    }

    // formatBuffer(buffer: ArrayBuffer) {
    //     var bufferArray = Object.keys(buffer).map(function (k) {
    //         return buffer[k];
    //     })
    //     return bufferArray
    // }

    getClientIP(req: any) {
        let ip = req.headers['x-forwarded-for'] || // 判断是否有反向代理 IP
            req.ip ||
            req.connection.remoteAddress || // 判断 connection 的远程 IP
            req.socket.remoteAddress || // 判断后端的 socket 的 IP
            req.connection.socket.remoteAddress || ''
        if (ip) {
            ip = ip.replace('::ffff:', '')
        }
        return ip;
    }

    onConnection(socket: ws, req: IncomingMessage) {
        let ag = new agent(socket);

        if (req) {
            let ip = this.getClientIP(req);
            ag.ip = ip;
        }

        socket.on("message", async (data: any) => {
            if (data == "ping") {
                ag.send("pong");
                return;
            }
            let recv = msgpack.decode(data);
            let msgId = recv.c;
            let msg = recv.d;
            let f = this.receiveFunc[msgId];
            if (f) {
                f(ag, msg);
                return;
            }
            console.error("未知的协议", msgId, JSON.stringify(msg));
        });

        socket.on("close", (code: number, reason: string) => {
            this.onAgentClose(ag, code, reason);
        });

        socket.on("error", (code: number, reason: string) => {
            this.onAgentClose(ag, code, reason);
        });

        let index = this.agentList.push(ag);
        ag.id = index - 1;

        lyu.event.emit(lNetEvent.agentConnected, ag);
    }

    onAgentClose(ag: agent, code: number, reason: string) {
        lyu.event.emit(lNetEvent.agentDisconnected, ag);
        ag.onClose(code, reason);
        this.agentList.splice(ag.id, 1);
    }

    onClose() {
        console.log(`[LNet]:Net关闭，端口${this.ws.options.port}`);
    }

    register(cmd: string | number, func: (ag: agent, data: any) => void) {
        this.receiveFunc[cmd] = func;
    }
}